package top.chengdongqing.mishop.utils

import org.springframework.data.redis.core.RedisTemplate
import org.springframework.stereotype.Component
import top.chengdongqing.mishop.common.sender.EmailSender
import top.chengdongqing.mishop.common.sender.SmsSender
import java.util.concurrent.TimeUnit
import kotlin.random.Random

/**
 * 验证码工具类
 */
@Component
class VerificationCodeUtils(
    private val redisTemplate: RedisTemplate<String, String>,
    private val emailSender: EmailSender,
    private val smsSender: SmsSender
) {

    fun sendByEmail(email: String) {
        val code = randomCode()
        val message = "Your verification code is: $code"
        emailSender.send(email, "验证码", message)
        storeCode(email, code)
    }

    fun sendBySms(phoneNumber: String) {
        val code = randomCode()
        val message = "Your verification code is: $code"
        smsSender.send(phoneNumber, "验证码", message)
        storeCode(phoneNumber, code)
    }

    private fun storeCode(recipient: String, code: String) {
        redisTemplate.opsForValue().set(recipient, code, CODE_EXPIRATION_SECONDS, TimeUnit.SECONDS)
    }

    fun verify(recipient: String, receivedCode: String): Boolean {
        if (recipient.isBlank() || receivedCode.isBlank()) {
            return false
        }

        val storedCode = redisTemplate.opsForValue().get(recipient)
        return (storedCode == receivedCode).also {
            if (it) {
                redisTemplate.delete(recipient)
            }
        }
    }

    fun verify(recipient: String, receivedCode: String, exception: () -> RuntimeException) {
        verify(recipient, receivedCode).also {
            if (!it) {
                throw exception()
            }
        }
    }
}

private const val DEFAULT_CODE_LENGTH = 6
private const val CODE_CHARACTERS = "0123456789"
private const val CODE_EXPIRATION_SECONDS = 300L

fun randomCode(length: Int = DEFAULT_CODE_LENGTH): String {
    return buildString {
        repeat(length) {
            val randomIndex = Random.nextInt(CODE_CHARACTERS.length)
            append(CODE_CHARACTERS[randomIndex])
        }
    }
}